from manim import *

# manim -qm -v WARNING LinearCoefficientChange.py
class LinearCoefficientChange(Scene):
    def construct(self):
        # 创建坐标轴
        axes = Axes(
            x_range=[-5, 5, 1],  # x 轴范围
            y_range=[-20, 100, 10],  # y 轴范围
            axis_config={"color": BLUE},
        )

        # 在坐标轴上添加刻度值
        axes.add_coordinates()

        # 添加坐标轴标签
        axis_labels = axes.get_axis_labels(x_label="x", y_label="y")

        # 初始二次函数（二次项系数 a = 10，一次项系数 b = -10）
        a_value = 10
        b_value = -10
        quadratic_function = axes.plot(lambda x: a_value * x**2 + b_value * x, color=YELLOW)

        # 动态显示二次函数的表达式
        function_label = MathTex("y = 10x^2 + bx").next_to(UP)  # 将表达式放在顶部

        # 动态显示一次项系数 b 的值，并添加 "b =" 字符串
        b_label = DecimalNumber(
            b_value,
            num_decimal_places=1,
            include_sign=True,
            color=YELLOW
        )
        b_text = Text("b = ", color=YELLOW).next_to(b_label, LEFT)
        b_group = VGroup(b_text, b_label).next_to(function_label, DOWN)  # 将 b 的值放在表达式下方

        # 添加所有对象到场景
        self.play(Create(axes), Write(axis_labels))
        self.play(Create(quadratic_function), Write(function_label), Write(b_group))
        self.wait(1)

        # 动态更新一次项系数 b
        for b in np.arange(-10, 10.1, 0.1):  # 从 -10 到 10，步长 0.1
            # 更新函数图像
            new_function = axes.plot(lambda x: a_value * x**2 + b * x, color=YELLOW)
            # 更新系数显示
            b_label.set_value(b)
            # 更新函数表达式
            new_function_label = MathTex(f"y = 10x^2 + {b:.1f}x").next_to(UP)
            # 播放动画
            self.play(
                Transform(quadratic_function, new_function),
                Transform(function_label, new_function_label),
                UpdateFromFunc(b_group, lambda m: m.next_to(function_label, DOWN)),
                rate_func=linear,
                run_time=0.05
            )

        # 保持显示
        self.wait(2)

# 运行脚本
if __name__ == "__main__":
    scene = LinearCoefficientChange()
    scene.render()